package base;

import config.ApiConfig;
import config.ApiPath;
import lombok.extern.slf4j.Slf4j;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.BeforeSuite;
import utils.AssertUtils;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import static base.HttpRequestExecutor.*;

@Slf4j
public class BaseTest {
    protected static ThreadLocal<Method> currentTestMethod = new ThreadLocal<>();

    // 加载自动化执行的环境变量，整个testSuite只需加载一次
    @BeforeSuite
    public static void loadEnvVariables() {
        // 加载自动化执行的环境变量配置文件，/resource/envVariables/${profile}.yaml
        String configFile = System.getProperty("configFile");
        log.info("Loading envVariables from: {}", configFile);

        try (InputStream inputStream = BaseTest.class.getClassLoader().getResourceAsStream(configFile)) {
            if (inputStream != null) {
                Properties properties = new Properties();
                properties.load(inputStream);

                // 设置系统属性
                for (String key : properties.stringPropertyNames()) {
                    System.setProperty(key, properties.getProperty(key));
                }

                log.info("envVariables loaded successfully");
            }
        } catch (IOException e) {
            log.error("Failed to load envVariables: {}", e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    @BeforeMethod
    public void setup(Method method) {
        currentTestMethod.set(method);
    }

    private static final ThreadLocal<Map<String, String>> testCaseVariables = new ThreadLocal<Map<String, String>>() {
        @Override
        protected Map<String, String> initialValue() {
            return new HashMap<>();
        }
    };

    // 修改占位符解析方法，优先从测试用例变量中获取
    protected static String getPlaceholderValue(String placeholder) {
        // 支持缺省值语法: ${variable:-default}
        String defaultValue = null;
        String actualPlaceholder = placeholder;

        // 检查是否包含缺省值
        int defaultIndex = placeholder.indexOf(":-");
        if (defaultIndex != -1) {
            actualPlaceholder = placeholder.substring(0, defaultIndex);
            defaultValue = placeholder.substring(defaultIndex + 2);
        }

        // 首先检查测试用例级别的变量
        String value = testCaseVariables.get().get(actualPlaceholder);
        if (value != null) {
            return value;
        }

        // 然后检查JVM系统属性(即多环境变量)
        value = System.getProperty(actualPlaceholder);
        if (value != null) {
            return value;
        }

        // 最后返回缺省值
        return defaultValue;

    }

    // 设置测试用例变量
    protected void setTestCaseVariable(String key, String value) {
        testCaseVariables.get().put(key, value);
    }

    // 批量设置测试用例变量
    protected void setTestCaseVariables(Map<String, String> variables) {
        testCaseVariables.get().putAll(variables);
    }

    // 清理测试用例变量
    protected void clearTestCaseVariables() {
        testCaseVariables.get().clear();
    }

    // 在测试方法执行前后自动清理
    @BeforeMethod
    public void setUpTestCase() {
        clearTestCaseVariables();
    }

    @AfterMethod
    public void tearDownTestCase() {
        clearTestCaseVariables();
    }

    protected String yamlDrive() {
        Method method = currentTestMethod.get();
        if (method != null) {
            ApiPath apiPath = method.getAnnotation(ApiPath.class);
            if (apiPath != null) {
                ApiConfig config = loadYamlSingle(apiPath.value());
                return HttpRequestExecutor.executeRequest(config);
            }
        }
        log.error("无法从注解获取YAML路径，请检查yaml路径是否正确");
        throw new IllegalStateException("无法从注解获取YAML配置");
    }

    // 处理多个请求的YAML文件
    protected List<String> yamlDriveMulti() {
        Method method = currentTestMethod.get();
        if (method != null) {
            ApiPath apiPath = method.getAnnotation(ApiPath.class);
            if (apiPath != null) {
                List<ApiConfig> configs = loadYamlMulti(apiPath.value());
                if (configs != null) {
                    return HttpRequestExecutor.executeMultipleRequests(configs);
                }
            }
        }
        log.error("无法从注解获取YAML路径，请检查yaml路径是否正确");
        throw new IllegalStateException("无法从注解获取YAML配置");
    }

    protected void yamlDriveAssert() {
        Method method = currentTestMethod.get();
        if (method != null) {
            ApiPath apiPath = method.getAnnotation(ApiPath.class);
            if (apiPath != null) {
                ApiConfig config = loadYamlSingle(apiPath.value());
                // 执行单个请求并获取响应
                String response = executeRequest(config);
                log.info("Response: {}", response);

                // 如果 assertion 字段存在，则进行断言
                if (config.getAssertion() != null) {
                    AssertUtils.performAssertions(response, config.getAssertion());
                }
            }
        }
        else {
            log.error("无法从注解获取YAML路径，请检查yaml路径是否正确");
            throw new IllegalStateException("无法从注解获取YAML配置");
        }

    }

    protected void yamlDriveAssertMulti() {
        Method method = currentTestMethod.get();
        if (method != null) {
            ApiPath apiPath = method.getAnnotation(ApiPath.class);
            if (apiPath != null) {
                List<ApiConfig> configs = loadYamlMulti(apiPath.value());

                List<String> responses = executeMultipleRequests(configs);
                for (int i = 0; i < configs.size(); i++) {
                    ApiConfig config = configs.get(i);
                    String response = responses.get(i);

                    if (config.getAssertion() != null) {
                        AssertUtils.performAssertions(response, config.getAssertion());
                    }
                }
            }
        }
        else {
            log.error("无法从注解获取YAML路径，请检查yaml路径是否正确");
            throw new IllegalStateException("无法从注解获取YAML配置");
        }

    }


}
